package com.cx.base.day19_thread;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.LockSupport;

import static java.lang.Thread.sleep;

/**
 * @Author: robert.song
 * @Date: Created in 2021/8/3
 */

/**
 * 与wait&notify比较：
 * wait/notify/notifyAll需要有锁资源下操作，不精确
 * park/unpark不需锁资源即可执行，线程精确
 * park也是今日waitting状态，这个waitting可以被interrupt()和unpark()恢复，interrupt会改变线程打断标记，而unpark不改变打断标记
 * park不会释放锁资源
 * park、unpark可以先unpark,但是notify必须先wait，否则IllegalMonitorStateException
 */
@Slf4j(topic = "Thread_4_park线程")
public class Thread_4_park线程 {
    public static void main(String[] args) {
//        test3();
        test4();
    }

    private static void test3() {
        Thread t1 = new Thread(() -> {
            synchronized (Thread_4_park线程.class) {
                try {
                    Thread_4_park线程.class.wait();
                } catch (InterruptedException e) {
                    // interrupt()方法会使线程的waitting状态中断，也会正常创建中断标识，只是会使线程抛中断异常，需要做下异常处理
                    System.out.println(Thread.interrupted());
                    e.printStackTrace();
                }
            }
            log.info("park...");
            LockSupport.park();
            log.info("unpark...其它线程执行了interrupt()" + "：打断状态：" + Thread.currentThread().isInterrupted());
//            此时打断标记为true，无法执行park()方法
            LockSupport.park();
            log.info("无法进入park，因为没有清除标记");
//            如想继续park,需要把打断标记改回false
            Thread.interrupted();
            log.info("清除标记，进入park");
            LockSupport.park();
            log.info("其它线程执行了unpark");
            log.info("unpark...");
        }, "t1");
        t1.start();

        try {
            sleep(1);
            t1.interrupt();
            sleep(1);
            t1.interrupt();
            sleep(1);
            LockSupport.unpark(t1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public static void test4() {
        Thread t1 = new Thread(() -> {
            synchronized (Thread_4_park线程.class) {
//            park中断是waitting中断，即使无锁也可以使当前的对象进入waitset等待，
//            这与wait()方法不同，wait()必须要获取锁才可执行
                Thread t = Thread.currentThread();
                log.debug(t.getName() + " state:" + t.getState().toString());
                LockSupport.park();
                log.debug("线程自己park");
//              等待主线程执行interrupt()
                log.debug("unpark 主线程执行了interrupt()" + "，打断标记：" + t.isInterrupted());
//            此时打断标记为true，无法执行park()方法
                LockSupport.park();
                log.debug("park失败 线程自己park失败，因为没有清除标记");
//            如想继续park,需要把打断标记改回false
                Thread.interrupted();
                log.debug("清除标记 线程自己执行Thread.interrupted()，进入park");
                LockSupport.park();
                log.debug("unpark 主线程执行了LockSupport.unpark(" + t.getName() + ")");
                log.debug("unpark 主线程执行了LockSupport.unpark(t2)" + "，打断标记：" + t.isInterrupted());
                while (true) {

                }
            }

        }, "t1");
        try {
            Thread t2 = new Thread(t1, "t2");
//            t1.start();
            sleep(1);
            t2.start();
//            可能没有遇到同步锁，此时可能是运行态
            log.debug(t2.getName() + " state:" + t2.getState().toString());
            sleep(1);
//            此时为waitting
            log.debug(t2.getName() + " state:" + t2.getState().toString());
//            恢复t2
            t2.interrupt();
            sleep(1);
            LockSupport.unpark(t2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
